import java.util.*;


//Note: References to "pitch" refer to the pitch class (e.g., C, Eb, B)
//      References to "note" refer to the pitch class of an NSNote object with its corresponding octave (e.g., C4)
//      To retrieve an NSNote (not a String "note"), use the get(index) method from Java's ArrayList interface

public class NSpace extends ArrayList<NSNote>{
  
  public NSpace(String notes) {
    notes = notes.replaceAll(" ", ""); //Remove All Whitespace
    String[] parsedNotes = notes.split(","); //Notes are delimited by commas
    
    for (int i = 0; i < parsedNotes.length; i++) {
      NSNote parsedNote = new NSNote(parsedNotes[i]); //For each parsed note string, create a note object
      super.add(parsedNote); //Add the note object to the ArrayList
    }
  }
  
  //At the index specified, insert the modified NSNote (held as a string)
  //into the occupied index housing the original NSNote.
  
  public void modify(String note, int index) {
    assert index >= 0;
    assert index < super.size();
   
    NSNote modifiedNote = new NSNote(note);
    super.set(index, modifiedNote);
  }
  
  //Similar to the method above, however, it deals directly with NSNote objects.
  public void modify(NSNote modifiedNote, int index) {
    assert index >= 0;
    assert index < super.size();
    super.set(index, modifiedNote);
  }
  
  //This method allows for the addition of notes to the NSpace by way of String values
  //N.B.: An inherited add() method from Java's ArrayList handles NSNotes separately
  public void add(String additionalNote) {
    NSNote addendum = new NSNote(additionalNote);
    super.add(addendum);
  }
  
  
  //Returns an integer array of each octave associated with each NSNote
  
  public int[] getOctaves() {
    int listSize = super.size();
    int[] octaveArray = new int[listSize];
    for (int i = 0; i < listSize; i++) {
      octaveArray[i] = (super.get(i)).getOctave();
    }
    return octaveArray;
  }
  
  //Returns the highest octave in the NSpace
  
  public int maxOctave() {
    int octave = (super.get(0)).getOctave();
    for (int i = 0; i < super.size(); i++) {
      if ((super.get(i)).getOctave() > octave) {
        octave = (super.get(i)).getOctave();
      }
    }
    return octave;
  }
  
  //Returns the lowest octave in the NSpace
  
  public int minOctave() {
    int octave = (super.get(0)).getOctave();
    for (int i = 0; i < super.size(); i++) {
      if ((super.get(i)).getOctave() < octave) {
        octave = (super.get(i)).getOctave();
      }
    }
    return octave;
  }
  
  //Returns a double-precision value array of all the frequencies associated with each NSNote
  
  public double[] getFreqs() {
    int listSize = super.size();
    double[] frequencyArray = new double[listSize];
    for (int i = 0; i < listSize; i++) {
      frequencyArray[i] = (super.get(i)).getFreq();
    }
    return frequencyArray;
  }
  
  //Returns the highest frequency in the NSpace
  
  public double maxFreq() {
    double freq = (super.get(0)).getFreq();
    for (int i = 0; i < super.size(); i++) {
      if ((super.get(i)).getFreq() > freq) {
        freq = (super.get(i)).getFreq();
      }
    }
    return freq;
  }
  
  //Returns the lowest frequency in the NSpace
  
  public double minFreq() {
    double freq = (super.get(0)).getFreq();
    for (int i = 0; i < super.size(); i++) {
      if ((super.get(i)).getFreq() < freq) {
        freq = (super.get(i)).getFreq();
      }
    }
    return freq;
  }
  
  //Returns a String array of all the pitch classes in the NSpace
  //Takes an input indicating whether the pitch classes returned are the mapped ('m') or the non-mapped ones ('nm')
  
  public String[] getPitches(String mapOption) {
    boolean validOption = false;
    boolean mapPitch = false;
    if (mapOption.equalsIgnoreCase("m")) {
      validOption = true;
      mapPitch = true;
    } else if (mapOption.equalsIgnoreCase("nm")) {
      validOption = true;
    }
    
    assert validOption = true;
    
    String[] pitchArray = new String[super.size()];
    
    for (int i = 0; i < super.size(); i++) {
      if (mapPitch == true) {
        pitchArray[i] = (super.get(i)).getMappedPitch();
      } else {
        pitchArray[i] = (super.get(i)).getPitch();
      }
    }
    
    return pitchArray;
    
  }
  
  //Return a String array of all the notes (pitch + octave) in the NSpace
  //Takes an input indicating whether the pitch classes returned are the mapped ('m') or the non-mapped ones ('nm')
  
  //N.B.: getNotes() and getNote() in the NSNote object refer to a String that is composed of the pitch class of a
  //given NSNote and the octave of that NSNote
  
  //To retrieve an NSNote object from an NSpace, use the get(index) operation taken from Java's ArrayList interface
  //E.g. NSpace.get(3) retrieves the NSNote at index position 3
  //E.g. NSpace.getNotes(3) retrieves the string of pitchclass+octave (ex. 'C4')
  
   public String[] getNotes(String mapOption) {
    boolean validOption = false;
    boolean mapPitch = false;
    if (mapOption.equalsIgnoreCase("m")) {
      validOption = true;
      mapPitch = true;
    } else if (mapOption.equalsIgnoreCase("nm")) {
      validOption = true;
    }
    
    assert validOption = true;
    
    String[] noteArray = new String[super.size()];
    
    for (int i = 0; i < super.size(); i++) {
      if (mapPitch == true) {
        noteArray[i] = (super.get(i)).getMappedPitch() + (super.get(i)).getOctave();
      } else {
        noteArray[i] = (super.get(i)).getPitch() + (super.get(i)).getOctave();
      }
    }
    
    return noteArray;
    
  }
   
   public String[] view() {
     String[] notesInSpace = this.getNotes("nm");
     return notesInSpace;
   }
    
    
  
}